using System.Collections.Generic;
using LiteTools.constants.enums;
using LiteTools.domains;
using LiteTools.domains.db;
using LiteTools.tools;

namespace LiteTools.service.converters.data_parser.tlv
{
    public class BerTlvParser : TypeTlv
    {
        public const string Flag = "BER-TLV";
        private static Dictionary<string, TagInfoHelper.TagInfo> TagInfosDict;

        protected override FormatData HandleTlv(string originText, List<TagInfoHelper.TagInfo> tagWhiteList)
        {
            TagInfosDict = new Dictionary<string, TagInfoHelper.TagInfo>();
            TagInfosDict.Clear();
            if (tagWhiteList != null)
            {
                foreach (var tagInfo in tagWhiteList)
                {
                    TagInfosDict.Add(tagInfo.tag_value, tagInfo);
                }
            }

            var tlvData = new TlvData
            {
                Tag = "root",
                Level = 0,
                TlvList = new List<TlvData>()
            };

            var tlvDataList = ParseTlv(originText, 1);
            tlvData.TlvList.AddRange(tlvDataList);
            // 写具体的解析TLV的实现
            return tlvData;
        }

        private static IEnumerable<TlvData> ParseTlv(string originText, int level)
        {
            var tlvDataList = new List<TlvData>();

            while (true)
            {
                var list = new List<TlvData>();
                var tlvData = new TlvData
                {
                    Tag = "",
                    Length = "0",
                    Value = "",
                    Level = level,
                    TlvList = new List<TlvData>()
                };
                if (string.IsNullOrEmpty(originText))
                {
                    return new List<TlvData>();
                }

                // 如果存在白名單的Tag就优先使用白名单的数据，并且做好数据的下一步分割
                if (TagInfosDict != null && TagInfosDict.Count > 0 && HasWhiteListTag(originText,
                        out var contextWithoutFirstTag, out _,
                        out var constructType))
                {
                    tlvData.Tag = originText.Substring(0, originText.Length - contextWithoutFirstTag.Length);
                }
                else
                {
                    tlvData.Tag = TlvUtil.GetTag(originText, out contextWithoutFirstTag, out _,
                        out constructType);
                }

                tlvData.Length = TlvUtil.GetLengthValue(contextWithoutFirstTag, out var contextNonLength);
                tlvData.Value = TlvUtil.GetValue(contextNonLength, tlvData.Length, out var nonValueContext);

                // 如果后面依然是结构，那也需要继续解析
                if (constructType == TlvTypeEnum.Constructed)
                {
                    var tlv = ParseTlv(tlvData.Value, level + 1);
                    tlvData.TlvList.AddRange(tlv);
                }

                list.Add(tlvData);

                // 如果后面还有，那就说明是并列的TLV，需要递归解析
                if (!string.IsNullOrEmpty(nonValueContext))
                {
                    list.AddRange(ParseTlv(nonValueContext, level));
                    // 到这里就处理完了，要把它的内容清空
                    nonValueContext = string.Empty;
                }

                tlvDataList.AddRange(list);
                if (string.IsNullOrEmpty(nonValueContext))
                {
                    return tlvDataList;
                }
            }
        }

        private static bool HasWhiteListTag(string context, out string contextWithoutFirstTag, out TlvClassEnum tagType,
            out TlvTypeEnum constructType)
        {
            string tag;
            if (TagInfosDict.ContainsKey(context.Substring(0, 2)))
            {
                tag = context.Substring(0, 2);
                contextWithoutFirstTag = context.Substring(2);
                tagType = TlvClassEnum.Specific;
                constructType = TagInfosDict[tag].tag_type == "0" ? TlvTypeEnum.Primitive : TlvTypeEnum.Constructed;
                return true;
            }

            if (TagInfosDict.ContainsKey(context.Substring(0, 4)))
            {
                tag = context.Substring(0, 4);
                contextWithoutFirstTag = context.Substring(4);
                tagType = TlvClassEnum.Specific;
                constructType = TagInfosDict[tag].tag_type == "0" ? TlvTypeEnum.Primitive : TlvTypeEnum.Constructed;
                return true;
            }

            if (TagInfosDict.ContainsKey(context.Substring(0, 6)))
            {
                tag = context.Substring(0, 6);
                contextWithoutFirstTag = context.Substring(6);
                tagType = TlvClassEnum.Specific;
                constructType = TagInfosDict[tag].tag_type == "0" ? TlvTypeEnum.Primitive : TlvTypeEnum.Constructed;
                return true;
            }

            contextWithoutFirstTag = context;
            tagType = TlvClassEnum.Normal;
            constructType = TlvTypeEnum.Unkown;
            return false;
        }
    }
}